﻿using AForge.Neuro;
using AForge.Neuro.Learning;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;

namespace redes_neuronales_ocr
{
    class CodigoAuxiliar
    {
        /// Se arma los valores de entrada en base a arrays de inputs, donde cada array representa una imagen de un unico caracter
        /// y se arma valores de salida que son un array de double(La salida son array con un solo double, se uso eso porque la red solo permitia usar arrays y no un double directo).
        /// Luego cada double tiene asociado un caracter.
        /// Despues de armar estos valores de entrada/salida, se entrena a la red.
        public void MainAuxiliar()
        {
            //string name = "C:\\Users\\Alan\\Documents\\Visual Studio 2010\\Projects\\TP1-IA\\redes-neuronales-ocr\\redes-neuronales-ocr\\Img1.png";
            string name = "C:\\Users\\Sebass\\Desktop\\Inteligencia Artificial\\workspace\\redes-neuronales-ocr\\redes-neuronales-ocr\\img-entrenamiento";

            // 25 Valores de entrada(25 arrays de doubles)
            double[][] valoresDeEntrada = new double[25][];

            DirectoryInfo directoryInfo = new DirectoryInfo(name);
            // Obtengo todas las imagenes de la carpeta
            FileInfo[] fileInfo = directoryInfo.GetFiles();
            //Por cada imagen, la paso a un array de 1 y 0.
            for (int z = 0; z < fileInfo.Length; z++)
            {
                FileInfo fileActual = fileInfo[z];

                string rutaAbsolutaDeImagen = fileActual.FullName;
                Bitmap img = new Bitmap(rutaAbsolutaDeImagen);

                double[] pixels = new double[250];//(250 = 50 * 50) REPRESENTO UNA MATRIZ CON VECTOR.

                int altoImagen = img.Height;
                int largoImagen = img.Width;

                for (int i = 0; i < largoImagen; i++)
                {
                    for (int j = 0; j < altoImagen; j++)
                    {
                        //En vez de una matriz hago un vector.
                        //Si es igual a blanco, pongo un 1, si no pongo un 0.
                        pixels[(i * largoImagen) + j] = img.GetPixel(i, j).Equals(Color.White) ? 1 : 0;
                    }
                }

                //Guardo cada array/matriz de doubles en los valores de entrada.
                valoresDeEntrada[z] = pixels;
            }

            /*************************************************************************************************************/
            /****************************************** Entrenamiento de la red ******************************************/
            /*************************************************************************************************************/

            int[] neuronasPorCapa = { 3, 5, 2 };
            ActivationNetwork red = new ActivationNetwork(new SigmoidFunction(), 4, neuronasPorCapa);
            //BackPropagationLearning aprendizaje = new BackPropagationLearning(red);
            BackPropagationLearning aprendizaje = new BackPropagationLearning(red);
            // Los valores de entrada son la matriz de colores y la de salida son un numero, el cual va a a estar asociado a una letra.
            // Esto se hace asi porque la red tiene como parametros de salida como doubles, entonces en vez de devolver un caracter,
            // devuelve un double, que esta asociado a un caracter.
            // Ejemplo, si la red devuelve 1, el caracter es A, 2 = b, etc..

            // Hacer esto en un for si se puede
            double[][] valoresDeSalida = { new double[] { 1 }, new double[] { 2 }, new double[] { 3 }, new double[] { 4 },
                                           new double[] { 5 }, new double[] { 6 }, new double[] { 7 }, new double[] { 8 }, 
                                           new double[] { 9 }, new double[] { 10 }, new double[] { 11 }, new double[] { 12 },
                                           new double[] { 13 }, new double[] { 14 }, new double[] { 15 }, new double[] { 16 },
                                           new double[] { 17 }, new double[] { 18 }, new double[] { 19 }, new double[] { 20 },
                                           new double[] { 21 }, new double[] { 22 }, new double[] { 23 }, new double[] { 24 },
                                           new double[] { 25 } };
            bool terminoElEntrenamiento = false;
            //VERIFICAR BIEN ESTE LOOP CUANDO TERMINAAAAAAAA
            while (!terminoElEntrenamiento)
            {
                double error = aprendizaje.RunEpoch(valoresDeEntrada, valoresDeSalida);

                if (error < 40)
                {
                    terminoElEntrenamiento = true;
                }
            }

            /*************************************************************************************************************/
            /********************************************** Uso de la red ************************************************/
            /*************************************************************************************************************/

            // Despues de entrenarla le paso una iamgen e imprimo su resultado.
            //Devuelve una lista de Indice Resultados (Esta lista v a atener 1 solo elemneto siempre, se usa una lista porque asi es la interfaz de la red, si no se usaria double directamente)
            double[] IndiceResultadoList = red.Compute(valoresDeEntrada[0]);

            double IndiceResultado = IndiceResultadoList[0];
            Dictionary<double, string> hashResultado = ObtenerHashOutput();

            string resultado;
            // En base al indice, obtengo el resultado correspondiente
            hashResultado.TryGetValue(IndiceResultado, out resultado);

            System.Console.WriteLine(resultado);
        }

        ///<summary>
        ///Devuelve un diccionario que tiene asosiado un double con un caracter
        ///</summary>
        ///<return>
        ///Devuelve un diccionario que tiene asosiado un double con un caracter
        ///</return>
        ///<param name="path">
        /// ---
        ///</param>
        static Dictionary<double, string> ObtenerHashOutput()
        {
            Dictionary<double, string> hash = new Dictionary<double, string>();
            hash.Add(1, "a");
            hash.Add(2, "b");
            hash.Add(3, "c");
            hash.Add(4, "d");
            hash.Add(5, "e");
            hash.Add(6, "f");
            hash.Add(7, "g");
            hash.Add(8, "h");
            hash.Add(9, "i");
            hash.Add(10, "j");
            hash.Add(11, "k");
            hash.Add(12, "l");
            hash.Add(13, "m");
            hash.Add(14, "n");
            hash.Add(15, "o");
            hash.Add(16, "p");
            hash.Add(17, "q");
            hash.Add(18, "r");
            hash.Add(18, "s");
            hash.Add(19, "t");
            hash.Add(20, "u");
            hash.Add(21, "v");
            hash.Add(22, "w");
            hash.Add(23, "x");
            hash.Add(24, "y");
            hash.Add(25, "z");

            return hash;
        }
    }
}